import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';

enum DkVisibilityFlag {
  visible,
  invisible,
  offscreen,
  gone,
}

///https://www.cnblogs.com/pjl43/p/9615685.html
///flutter中如何较好地实现隐藏和显示widget
class DkVisibilitySingle extends StatelessWidget {
  final DkVisibilityFlag visibility;
  final Widget child;
  final Widget removeChild;

  DkVisibilitySingle({
    @required this.child,
    @required this.visibility,
  }) : this.removeChild = Container();

  @override
  Widget build(BuildContext context) {
    if (visibility == DkVisibilityFlag.visible) {
      return child;
    } else if (visibility == DkVisibilityFlag.invisible) {
      return IgnorePointer(
          ignoring: true, child: new Opacity(opacity: 0.0, child: child));
    } else if (visibility == DkVisibilityFlag.offscreen) {
      return Offstage(offstage: true, child: child);
    } else {
      return removeChild;
    }
  }
}

class DkVisibilityCompose extends Visibility {
  final VisibilityComposeOption visibilityComposeOption;

  DkVisibilityCompose(this.visibilityComposeOption)
      : super(
          key: visibilityComposeOption.key,
          child: Builder(
            builder: (BuildContext context) {
              return visibilityComposeOption.childBuilder(context);
            },
          ),
          replacement: Builder(
            builder: (BuildContext context) {
              return visibilityComposeOption.replacementBuilder(context);
            },
          ),
          visible: visibilityComposeOption.visible,
          maintainState: visibilityComposeOption.maintainState,
          maintainAnimation: visibilityComposeOption.maintainAnimation,
          maintainSize: visibilityComposeOption.maintainSize,
          maintainSemantics: visibilityComposeOption.maintainSemantics,
          maintainInteractivity: visibilityComposeOption.maintainInteractivity,
        );
}

class VisibilityComposeOption {
  Key key;
  WidgetBuilder childBuilder;
  WidgetBuilder replacementBuilder;
  bool visible = true;

  bool maintainState = false;

  ///保持动画时必须设置maintainState = true；
  bool maintainAnimation = false;

  ///保持尺寸时必须设置maintainAnimation = true
  bool maintainSize = false;

  ///只能在保持尺寸时被设置
  bool maintainSemantics = false;

  ///只能在保持尺寸时被设置
  bool maintainInteractivity = false;

  VisibilityComposeOption(this.childBuilder,
      {this.key,
      this.replacementBuilder,
      this.visible,
      this.maintainState,
      this.maintainAnimation,
      this.maintainSize,
      this.maintainSemantics,
      this.maintainInteractivity}) {
    checkOption();
  }

  VisibilityComposeOption.gone(
    this.childBuilder, {
    this.key,
    this.visible,
    this.maintainState,
    this.maintainAnimation,
  }) {
    maintainSize = false;
    replacementBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };

    childBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    visible ??= true;
    maintainState ??= false;
    maintainAnimation ??= false;
    if (maintainAnimation) {
      maintainState = true;
    }
    maintainSemantics ??= false;
    maintainInteractivity ??= false;
  }

  VisibilityComposeOption.invisible(
    this.childBuilder, {
    this.key,
    this.visible,
    this.maintainState,
    this.maintainAnimation,
  }) {
    maintainSize = true;
    maintainAnimation = true;
    maintainState = true;
    replacementBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };

    childBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    visible ??= true;
    maintainSemantics ??= false;
    maintainInteractivity ??= false;
  }

  VisibilityComposeOption.replaceWithSize(
    this.childBuilder,
    this.replacementBuilder, {
    this.key,
    this.visible,
    this.maintainState,
    this.maintainAnimation,
  }) {
    maintainSize = true;
    maintainAnimation = true;
    maintainState = true;

    childBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    replacementBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    visible ??= true;
    maintainSemantics ??= false;
    maintainInteractivity ??= false;
  }

  VisibilityComposeOption.replaceWithOutSize(
    this.childBuilder,
    this.replacementBuilder, {
    this.visible,
    this.maintainState,
    this.maintainAnimation,
  }) {
    maintainSize = false;
    maintainSemantics = false;
    maintainInteractivity = false;

    childBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    replacementBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    visible ??= true;
    maintainState ??= false;
    maintainAnimation ??= false;
    if (maintainAnimation) {
      maintainState = true;
    }
  }

  void checkOption() {
    childBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    replacementBuilder ??= (BuildContext context) {
      return SizedBox.shrink();
    };
    visible ??= true;
    maintainState ??= false;
    maintainAnimation ??= false;
    maintainSize ??= false;
    maintainSemantics ??= false;
    maintainInteractivity ??= false;
    if (!maintainState && maintainAnimation) {
      maintainAnimation = false;
    }
    if (!maintainAnimation && maintainSize) {
      maintainSize = false;
    }
    if (!maintainSize && maintainSemantics) {
      maintainSemantics = false;
    }
    if (!maintainSize && maintainInteractivity) {
      maintainInteractivity = false;
    }
  }
}
